/*********************************************************************************
 *      Copyright:  (C) 2024 LingYun<iot25@lingyun>
 *                  All rights reserved.
 *
 *       Filename:  client_main.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(07/12/24)
 *         Author:  LingYun <iot25@lingyun>
 *      ChangeLog:  1, Release initial version on "07/12/24 17:45:14"
 *                 
 ********************************************************************************/
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sqlite3.h>
#include <pthread.h>

#include "get_time.h"
#include "get_temperature.h"
#include "socket_cnn.h"
#include "sqlite_database.h"
#include "log_system.h"
#include "thread.h"

void ignore_sigpipe();
void sample_data(sqlite3 *db);
char *upload_data(int client_fd,sqlite3 *db);

pthread_mutex_t db_mutex;

void *thread_workbody(void *arg);

struct option  opts[]=
{
	{"ipaddr", required_argument, NULL, 'i'},
    {"port", required_argument, NULL, 'p'},
	{"time_interval", required_argument, NULL, 't'},
    //{"num_threads",required_argument,NULL,'n'},
    {"debug", no_argument, NULL, 'd'},
    {"help", no_argument, NULL, 'h'},
    {NULL, 0, NULL, 0}
};

void print_usage(char *progname)
{
	printf("%s usage:\n",progname);
    printf("-i(--ipaddr):sepcify server ipaddr.\n");
	printf("-p(--port):sepcify server listen port.\n");
    printf("-t(--time_interval):send data interval.\n");
    //printf("-n(num_threads)):client_thread num.\n");
    printf("-d(--debug):  specify program running in debug mode\n");
    printf("-h(--help):   print this help information\n");

    printf("\nExample: %s -i 127.0.0.1 -p 8899 -t 5 -n 5 -d\n", progname);

	return ;
}

// 忽略 SIGPIPE 信号的函数
void ignore_sigpipe()
{
    signal(SIGPIPE, SIG_IGN);
}

//间隔采样函数，每retry秒进行一次采样
void sample_data(sqlite3 *db)
{
	char		buf[1024];
	char		time_buf[80];
	float		temperature;

	//获取温度数据和当前时间
	memset(buf,0,sizeof(buf));
	temperature = get_temperature();
	get_time(time_buf,sizeof(time_buf));

	snprintf(buf, sizeof(buf), "temperature:%f,time:%s", temperature, time_buf);

	//将温度数据存储到数据库中
	insert_data(db,buf);
	log_write(LOG_INFO, __FILE__, __func__, __LINE__, "采样数据: %s,且成功保存到数据库中", buf);

	return ;
}

//上传数据函数，每 time_interval 秒上传一次
char *upload_data(int client_fd, sqlite3 *db) 
{
    char	buf[1024];
	int		rc;
	char 	*result = NULL;

	rc = select_data(db,buf);
	if(rc != SQLITE_OK)
	{
		// 查询失败，记录错误日志并返回 NULL
		log_write(LOG_ERROR,__FILE__,__func__,__LINE__,"查询失败:%s",strerror(errno));
		pthread_mutex_unlock(&db_mutex);  // 解锁
		return NULL;
	}

    // 读取最新的温度数据并上传
    if (write_data(client_fd, buf, strlen(buf)) < 0) 
	{
		return NULL;
    }
	
	//发送成功之后就删除数据库中的数据
	result = strdup(buf);  //在这里动态分配内存
	if(result == NULL)
	{
		log_write(LOG_ERROR, __FILE__, __func__, __LINE__, "内存分配失败");
        return NULL;
	}

	//确保在删除数据后不再使用 result
    delete_data(db, result);
	return result;  //返回动态分配的字符串
}

int main(int argc,char **argv)
{
	int				client_fd = -1;
	int				cnn_status_fd = -1;

	char			*ipaddr = NULL;
	int				port = 0;
	int 			time_interval = 0;   //上传间隔
	int				retry_interval = 5; //采样间隔
	//int				num_threads = 1;
	int				ch;
	char			*progname = argv[0];

	sqlite3			*db;
	int				rc;

	char			*buf;

	// 初始化日志系统，日志级别为DEBUG，输出到控制台和文件
    log_init("client_program.log", LOG_DEBUG, 1);

	// 初始化互斥锁
    if (pthread_mutex_init(&db_mutex, NULL) != 0)
    {
        log_write(LOG_ERROR, __FILE__, __func__, __LINE__, "初始化互斥锁失败");
        return EXIT_FAILURE;
    }

	// 解析命令行参数
	while( (ch = getopt_long(argc,argv,"i:p:t:db",opts,NULL)) != -1 )
	{
		switch(ch)
		{
			case 'i':
				ipaddr = optarg;
				break;

			case 'p':
				port = atoi(optarg);
				break;

			case 't':
				time_interval = atoi(optarg);
				break;

			case 'h':
				print_usage(progname);
				log_write(LOG_INFO, __FILE__, __func__, __LINE__, "显示帮助信息");
				return EXIT_SUCCESS;

			default:
				print_usage(progname);
				log_write(LOG_ERROR, __FILE__, __func__, __LINE__, "命令行参数错误");
				return EXIT_FAILURE;
		}
	}

	//检查命令行是否输入正确
	if( !(ipaddr && port && time_interval))
	{
		print_usage(progname);
		log_write(LOG_ERROR, __FILE__, __func__, __LINE__, "缺少必要参数");
		return EXIT_FAILURE;
	}

	printf("IP:%s,端口号：%d,时间间隔：%d\n",ipaddr,port,time_interval);

	signal(SIGPIPE, SIG_IGN);

	rc = sqlite3_open("clientdata.db",&db);  //打开数据库，如果没有就创建
	
	if(rc < 0)
	{
		log_write(LOG_ERROR, __FILE__, __func__, __LINE__, "无法打开数据库: %s", sqlite3_errmsg(db));
		return EXIT_FAILURE;
	}

	//创建表，如果表已存在则不创建
	rc = create_db_and_table(db);
	if( rc != SQLITE_OK )
	{
		sqlite3_close(db);
		log_write(LOG_ERROR, __FILE__, __func__, __LINE__, "无法打开数据库: %s", sqlite3_errmsg(db));
		return rc;
	}

	client_fd = client_connect_to_server(ipaddr,port);

	time_t last_upload_time = 0;
	time_t last_sample_time = 0;

	// 将 time_t 转换为本地时间结构
    struct tm *upload_time_info = localtime(&last_upload_time);
    struct tm *sample_time_info = localtime(&last_sample_time);
 
	// 格式化时间字符串
    char upload_time_str[80];
    char sample_time_str[80];

    strftime(upload_time_str, sizeof(upload_time_str), "%Y-%m-%d %H:%M:%S", upload_time_info);
    strftime(sample_time_str, sizeof(sample_time_str), "%Y-%m-%d %H:%M:%S", sample_time_info);

	while(1)
	{
		time_t current_time = time(NULL);

		//每retry_interval 秒采样一次数据
		if(current_time - last_sample_time >= retry_interval)
		{
			sample_data(db);  // 采样数据
			last_sample_time = current_time;  // 更新上次采样时间
		}


		//检查连接状态，如果连接断开则重新连接
		cnn_status_fd = cnn_status(client_fd);

		if( cnn_status_fd <= 0)
		{
			log_write(LOG_ERROR,__FILE__,__func__,__LINE__,"连接断开，尝试重新连接。。。");
			client_fd = cnn_retry(&client_fd,ipaddr,port);
		}

		//每time_interval秒上传一次数据
		if( current_time - last_upload_time >= time_interval )
		{
			if( (buf = upload_data(client_fd,db)) == NULL )
			{
				log_write(LOG_ERROR, __FILE__, __func__, __LINE__, "数据发送失败，关闭连接");
				client_fd = -1;
				continue;
			}
			
			last_upload_time = current_time;   //更新上次上传时间
			log_write(LOG_INFO, __FILE__, __func__, __LINE__, "client_fd[%d]成功发送数据: %s", client_fd,buf);
			free(buf); // 释放动态分配的内存
		}
	}
	// 销毁互斥锁
    pthread_mutex_destroy(&db_mutex);
	sqlite3_close(db);
	return EXIT_SUCCESS;
}
